DDSキットとPICの接続
秋月のDDSキットですが、うまく組み立てられましたでしょうか。組立の詳細は、前の方のページにある「DDSキットを組み立てよう!」で掲載しています。
組立の際には、図1に示すように「J1」というジャンパーや、シリアル設定のジャンパーがありますので、これらを忘れずに接続しておいてください。チップセレクト端子が3カ所ありますが、ここではオープンのままでよいでしょう。DDS基板上で10kΩの抵抗で5Vにプルアップされています。(したがって、チップセレクトはCS2=「H」、CS1=「H」、CS0=「H」となり、シリアル入力のアドレスは、7となります。)図1の写真では、ディップスイッチが取り付けられていますが、あらかじめパラレル設定でDDSが動作していることを確認したかったためスイッチが取り付けられています。今回のようにシリアル設定で行う場合には特に取り付ける必要はありません。
![]() |
| 図1.秋月DDSキット |
DDS基板にあるシリアル入力の(1)STB、(2)DATA、(3)SCKの各端子は、表1に示すようにPIC16F877のREポート側に接続しました。PIC16F877のREポートは、ちょうどポートが3つあるので、ここのポートを選びました。REポートでなければならないという理由は特にありません。
| DDS側のシリアル 入力端子 |
PIC16F877側の 接続ポート |
| STB | RE0 |
| DATA | RE1 |
| SCK | RE2 |
図2はDDSキットとPICを接続したときの全体の様子を写真に撮りました。DDSキットの出力端子には、オシロスコープを接続して出力信号波形が観測できるようにしておきます。図3は、PICのREポートに接続されたときの様子を示しています。PICターゲットボードですが、ボードが汎用的に使えるように、DDSとの接続には10ピンのコネクタなどを使って取り外しが容易にできるようにしてあります。また、ボード上にはバッファ回路を通してLEDが取り付けられており、ポートに信号が出力されると光るようになっています。
![]() |
![]() |
| 図2.DDSキットとPICの接続 | 図3.PIC16F877のREポートに接続 |
図4に、PICターゲットボードとDDSキットとの概略接続図を示します。PICリセット後、確認のため
PORTB の LED が1秒間点灯するようにLEDを接続しています。(注)図中、RBの全ポートにLEDを接続していますが、いずれか1ポートにLED1個を接続しておけば確認は可能です。その他、未接続端子はオープンとします。
![]() |
| 図4.PICターゲットボードとDDSキットとの概略接続図 |
DDSの動作テストプログラム(1)
図5にDDSの動作テストのフローチャートを示します。プログラムの解説については、「プログラムの説明(1)」の項をご参照ください。リセット後、PICが動作していることを簡単に確認するため、PORTBに接続されたLEDが1秒間点灯します。DSSの設定ですが、
メモリ 1CH に周波数データ(10MHz)を書き込み、それと同時に出力するDDSコマンドCの動作テストになっています。周波数データやDDSのコマンドは、プログラム中のTABLEと記載されたラベルのところに、まとめてビット単位で並べられていますので、ここを変更すれば周波数やコマンドを変えることができます。
![]() |
| 図5.DDSの動作テストプログラムのフローチャート |
(注)以下に示すプログラムには、ホームページ画面作成の都合上、空白として全角文字のスペースなどが挿入されています。したがって、下記プログラムリストをそのままコピーしてMPLABのソースファイルとされた場合には、エラーとなることがあります。
→ここをクリックして、下記のプログラムをダウンロードするようにしてください。
ファイル名:「dds_1.asm」 サイズ4.59kバイト
→ここをクリックして、下記のオブジェクトファイルをダウンロードするようにしてください。
ファイル名:「dds_1.hex」 サイズ590バイト
|
;*********************************************************** ; DDS 動作チェックプログラム1 ; ;【 テスト内容 】 ; リセット後、確認のため PORTB の LED が1秒間点灯した後、 ; DSS メモリ 1CH に周波数データ(10MHz)を書き込み、それと同 ; 時に10MHzを出力する。(DDSコマンドCの動作テスト) ; ;【 接続ポート 】 ; (DDS) (PIC) ; STB ………RE0 ; DATA………RE1 ; SCK ………RE2 ; ;【 DDS チップセレクト 】 ; CS0 ………1 ; CS1 ………1 ; CS2 ………1 ; ;*********************************************************** |
|
|
LIST P=PIC16F877 INCLUDE P16F877.INC |
;(1)プロセッサの種別指定 ;(2)インクルードファイルの指定 |
|
;*********************************************************** ; 変数定義とレジスタ割付 ;*********************************************************** |
|
|
COUNT EQU 20H COUNT1 EQU 21H COUNT2 EQU 22H COUNT3 EQU 23H COUNT4 EQU 24H TEMP EQU 25H POINT EQU 26H |
;(3)ループカウンタ ; ループカウンタ1 ; ループカウンタ2 ; ループカウンタ3 ; ループカウンタ4 ; 一時保管データ ; テーブルポインタ |
|
;*********************************************************** ; 初期化 ;*********************************************************** |
|
| ORG 0 BSF STATUS,RP0 MOVLW B'00000010' MOVWF ADCON1 CLRF TRISE CLRF TRISB BCF STATUS,RP0 |
;(4)プログラムの開始番地の指定 ;(5)Bank 1 へ切替 ;(6)RE0,RE1,RE2 デジタル入出力 ; ADCON1レジスタの設定 ;(7)PORTE 全ポートを出力に設定 ;(8)PORTB 全ポートを出力に設定 ;(9)Bank 0 へ戻す |
|
;*********************************************************** ; メインプログラム ;*********************************************************** |
|
| MOVLW B'00000111' MOVWF PORTE LED_ON MOVLW B'11111111' MOVWF PORTB CALL TIME1S MOVLW B'00000000' MOVWF PORTB MOVLW 21H MOVWF POINT SET_DATA MOVF POINT,W CALL TABLE MOVWF TEMP BTFSS TEMP,0 GOTO DATA_L GOTO DATA_H SET_SCK BCF PORTE,2 NOP BSF PORTE,2 DECFSZ POINT,F GOTO SET_DATA BSF PORTE,1 NOP BCF PORTE,0 NOP BSF PORTE,0 |
;(10)SCK,DATA,STB = [H],[H],[H] に設定 ; PORTEへ出力(DDSとの通信の初期設定) ; ;(11)11111111 を Wreg にロードする ; PORTBへWregのデータを出力(LEDの全点灯) ;(12)1秒のウエイトを入れる ;(13)00000000 を Wreg にロードする ; PORTBへWregのデータを出力(LEDの消灯) ; ;(14)21H = 33回繰り返す(DDSとのデータ通信) ; テーブルポインタのセット ;(15)テーブルポインタの値をWregへロードする(OFFSET) ;(16)周波数データの読み込みサブルーチンへ ;(17)一時保管データへ ;(18)データが1だったら次の命令をスキップ ; DATA = [L] ; DATA = [H] ;(19)SCK = [L] ;(20)ポートの誤動作防止 ;(21)SCK = [H] ;(22)テーブルポインタ −1 ; SET_DATA のラベルへ戻り繰り返す ;(23)DATA = [H] ;(24)ポートの誤動作防止 ;(25)STB = [L] ;(26)ポートの誤動作防止 ;(27)STB = [H] |
END_LP GOTO END_LP DATA_L BCF PORTE,1 GOTO SET_SCK DATA_H BSF PORTE,1 GOTO SET_SCK |
;(28)DDS 設定終了 ;(29)DATA = [L] ;(30)DATA = [H] |
| ;*********************************************************** ; 周波数データテーブル ;*********************************************************** |
|
| TABLE ADDWF PCL,F NOP |
;(31)TABLEの定義(PC+OFFSET相当のデータを持って戻る) ; PC+OFFSET ;(32)ダミーデータ |
| DT 0,0,1,0,0,1,1,0,0,0,1,0,0,1,0,1,1,0,1,0,0,0,0,0,0,0 | |
DT 1,1,0,0 DT 1,1,1 |
;(33)f=10.000000MHz ;(34)コマンドC ;(35)CS2,CS1,CS0 = 1,1,1 |
| ;*********************************************************** ;遅延サブルーチン ;*********************************************************** ;100μs遅延サブルーチン(20MHzクロック時) ;・・・・・別記プログラムリスト参照・・・・・ ; ;10ms遅延サブルーチン(20MHzクロック時) ;・・・・・別記プログラムリスト参照・・・・・ ; ;1s遅延サブルーチン(20MHzクロック時) ;・・・・・別記プログラムリスト参照・・・・・ |
|
END |
|
【プログラムの説明(1)】![]()
このプログラムについて、順を追って解説を加えておきましょう。
(1)プロセッサの種別指定
定義の仕方は「PROCESSOR」か「LIST」命令を使って設定します。ここで指定するプロセッサ名称は、パッケージの種類を示すサフィックス(最後の英記号の部分)は不要です。
PROCESSOR PIC16F877
または
LIST P=PIC16F877
(2)標準ヘッダーファイルのインクルード
標準ヘッダーファイルとは、各プロセッサが持っているSFR(Special Function Register)をラベル(記号)で使える
ため、ラベルとハードウェアの場所とを定義しているファイルです。標準ヘッダーファイルは 「プロセッサ名.INC」というファイル名で統一されて、MPLABのディレクトリに格納されています。従って、これのインクルード方法は下記のようにして行います。
一度、参考までに標準ヘッダーファイルの内容をエディタ等で見ておくことをお勧めします。
INCLUDE P16F877.INC
または
#INCLUDE P16F877.INC
(3)変数定義とレジスタ割付
レジスタファイルアドレスを指定するときに、アドレス数値を直接指定することもできますが、数値だけでは間違いも多く、プログラム自身も分かりにくくなってしまいます。そこで、EQU命令などを使ってラベルを設定し変数を定義します。レジスタファイルアドレスは、7ビットあるので、00〜7Fまで最大128個のレジスタが指定できますが、実際に物理的に実装されて汎用的に使用できるレジスタ数はデバイスによって異なっていますので注意が必要です。
PIC16F877の汎用レジスタのアドレスは、20H〜7FH
となっていますので、20H以降のアドレスに割り付けます。
(4)プログラムの開始番地の指定
「ORG」はプログラムの開始番地を指定する擬似命令で、ORG以下の実際のプログラム命令が格納されるプログラムメモリ内の位置(アドレス)を指定します。
ORG 0 ;0番地から格納することを示します。
コンピュータは一般に電源投入時やリセットをすると必ず0番地からスタートするようになっているので、0番地には必ず命令があることが必要です。
(5)Bank 1 へ切替
PICには各種の動作モードを設定するための Special
Register と呼ばれるものが用意されています。PICを動作させるためには、まずこのSpecial
Registerの設定から始めます。そしてそれらは全て、Register
File と呼ぶメモリとして用意されています。その
Register Fileは Bank0, Bank1, Bank2, Bank3
とよばれるアドレス空間をもっているため、多少アクセスの仕方が面倒です。つまりRESET後の通常はBank0となっているので、Bank1側のレジスタにアクセスするときはBankの切替えをしてからとなります。またBank0とBank1に同じ物があるときにはどちらでも同じ様に使えます。
Bank1へ切り替える方法ですが、「STATUS」レジスタにある2ビットのRP0、RP1を変えてBankを指定します。デフォルトは、Bank0です。表2にBankとRP1,RP0ビットとの関係を示します。Bank1へ切り替えるためには、RP0ビットを「1」にします。(RP1はデフォルトで「0」なので変える必要はない。)
BSF STATUS,RP0
「STATUS」レジスタのRP0ビットを「1」にする。
| Bank | RP1 | RP0 |
| 0 | 0 | 0 |
| 1 | 0 | 1 |
| 2 | 1 | 0 |
| 3 | 1 | 1 |
(6)RE0,RE1,RE2 デジタル入出力
ADCON1レジスタの設定
![]()
REポートをディジタル入出力ポートとして使用するためには、ADCON1レジスタの設定が必要
REポートをディジタル入出力ポートとして使用するためには、ADCON1レジスタの設定が必要になります。PICのリセット後は、REポートがA/D変換の入力ポートになっているからです。(RAポートも同様)ADCON1レジスタの3〜0ビット(PCFGx)の設定内容より決定します。PCFGx=「0010」
or 「0011」 or 「0100」 or 「0101」 or 「0110」 or 「0111」 or 「1100」
or 「1101」 or 「1110」 or 「1111」のいずれかのときREポートはディジタル入出力ポートになることが分かります。(このとき、RAポートは使用しないので、RAポートの設定は無関係とします)
ADCON1レジスタの設定内容の詳細は、こちらをご覧ください。→ADCON1レジスタの設定内容について
なお、ADCON1レジスタの7〜4ビットは、簡単のためとりあえず「0」とでもしておき、またPCFGx=「0010」とすることで、すなわち、「ADCON1→B’00000010’ (2H)」に設定することで、REポートをディジタル入出力ポートとして使用することができます。
(7)PORTE 全ポートを出力に設定
TRISEレジスタを、CLRF(fレジスタをゼロクリアする命令)で出力設定とします。
CLRF TRISE
「TRISEレジスタをゼロクリアする。すなわち、PORTE全ポートを出力に設定する」
(8)PORTB 全ポートを出力に設定
TRISBレジスタを、CLRF(fレジスタをゼロクリアする命令)で出力設定とします。
CLRF TRISB
「TRISBレジスタをゼロクリアする。すなわち、PORTB全ポートを出力に設定する」
PORTBにはLEDが接続されており、DDSへシリアル入力する状態に入ったときの確認のために、点灯するようにしています。
(9)Bank 0 へ戻す
Bank1での設定が終了した後は、Bank0に戻しておきます。Bank1へ切り替えるためには、RP0ビットを「0」にします。(RP1はデフォルトで「0」なので変える必要はない。)
BCF STATUS,RP0
「STATUS」レジスタのRP0ビットを「0」にする。すなわち、Bank0に戻す。」
(10)SCK,DATA,STB = [H],[H],[H] に設定
PORTEへ出力(DDSとの通信の初期設定)
DDSとのシリアル通信を行う前に、信号ライン(SCK,DATA,STB)をすべて「H」に初期設定しておきます。
(11)11111111 を Wreg にロードし、
PORTBへWregのデータを出力(LEDの全点灯)
ここで、レジスタの初期設定が終了し、DDSへシリアル入力する状態に入ったことを確認するため、
PORTB の LED を全点灯させるようにします。
(12)1秒のウエイトを入れる
PORTB の LED の点灯時間を1秒間に設定します。ここでは、遅延サブルーチンを使っています。
(13)00000000 を Wreg にロードし、
PORTBへWregのデータを出力(LEDの消灯)
点灯していたLEDを消灯させ、DDSへシリアル入力開始の状態に入ったことを知らせます。
(14)21H = 33回繰り返す(DDSとのデータ通信)
テーブルポインタのセット
DDSへの入力データ(3ビットのアドレスデータ、4ビットのコマンドデータ、26ビットの周波数データ 計33ビット分)が、あらかじめテーブルに記載してあり、その33ビット分を1ビットずつ読み込んでくるようにテーブルポインタを設定しておきます。
(15)テーブルポインタの値をWregへロードする(OFFSET)
テーブルに記載されているデータを読み込んでくるため、テーブルポインタの値をWregにロードします。テーブルポインタの値は、プログラムカウンタにテーブルポインタの値(OFFSET分)を足し合わせることで、DDSへの入力データ(3ビットのアドレスデータ、4ビットのコマンドデータ、26ビットの周波数データ 計33ビット分)が記載されたテーブルの位置関係を指し示すようになっています。
(16)周波数データの読み込みサブルーチンへ
DDSへの入力データ(3ビットのアドレスデータ、4ビットのコマンドデータ、26ビットの周波数データ 計33ビット分)が記載されたテーブルから、1ビットずつ読み込むサブルーチンへ飛びます。
(17)一時保管データへ
DDSへの入力データテーブルから、1ビット分の読み込まれたデータを一時保管しておきます。
(18)データが1だったら次の命令をスキップ
DATA = [L] か DATA = [H] かの条件分岐
1ビット分の読み込まれたデータが、1だったらDDSへのDATA信号ラインを[H]に、0だったらDDSへのDATA信号ラインを[L]にする条件分岐になります。
(19)SCK = [L]
DDSへのSCK信号ラインを[L]にします。
(20)ポートの誤動作防止
![]()
BSF,BCFなどのビット操作命令で、同じポートに出力する場合には、間にダミーとしてNOP命令などを入れる
ここは、(19)と(21)のように、BSF,BCFなどのビット操作命令により同一ポートを続けて設定していると、ポートが誤動作をすることがあるので、ダミーとしてNOPを入れています。BSF,BCFなどのビット操作命令は、一度ポートレジスタのすべてのビットの状態を読み込み、指定ビットのみを変更して再度ポートレジスタに上書きするという操作がされます。すなわち、最初の命令(19)の出力がなされ、次の命令(21)が出力される前に、一度入力動作があるのです。最初の命令の出力と次の命令の入力動作の間は、1クロック分しかなく、20MHzクロックの場合にはわずかに50nsecです。出力ピンの負荷に何らかの容量成分があると、信号の立ち上がりや立ち下がりが遅れるため、最初の命令の出力が完全に落ち着く前に次の命令で読み込みを実行してしまうため誤動作が発生しやすくなります。この対策としては、ビット操作命令で連続して同じポートに出力する場合には、間にNOP命令など他の命令を最低1個挿入するようにします。
(21)SCK = [H]
DDSへのSCK信号ラインを[H]にします。このとき、SCKの立ち上がりでDATAが読み込まれます。
(22)テーブルポインタ −1
SET_DATA のラベルへ戻り繰り返す
テーブルポインタの値を1ずつ減らしていきます。テーブルポインタの値は、DDSへの入力データ(3ビットのアドレスデータ、4ビットのコマンドデータ、26ビットの周波数データ 計33ビット分)が記載されたテーブルの位置関係を指し示します。テーブルポインタの値が0になるまで(すべての入力データが読み込まれるまで)、SET_DATAとあるラベルへ戻り、DATAの読み込み動作を繰り返します。
(23)DATA = [H]
すべてのDATAがDDSへ送り終えたら、DATA信号ラインを「H」に設定しておきます。
(24)ポートの誤動作防止
ここは、(23)と(25)のように、BSF,BCFなどのビット操作命令を使って、同じポートに出力する場合には、間にダミーとしてNOP命令などを入れる。(20)参照
(25)STB = [L]
DDSへのSTB信号ラインを[L]にします。このとき、STBの立ち下がりで、読み込まれたコマンド・データが実行され、DDSの出力端子から10MHzの信号が出力されます。
(26)ポートの誤動作防止
ここは、(25)と(27)のように、BSF,BCFなどのビット操作命令を使って、同じポートに出力する場合には、間にダミーとしてNOP命令などを入れる。(20)参照
(27)STB = [H]
STB信号ラインを「H」に設定して終了します。
(28)DDS 設定終了
DDSの設定が終了した後、PIC側の動作としては、END_LPのラベル間をループさせておしまい。
(29)DATA = [L]
(18)の分岐命令で、1ビット分の読み込まれたデータが、0だったらDDSへのDATA信号ラインを[L]にするルーチン。
(30)DATA = [H]
(18)の分岐命令で、1ビット分の読み込まれたデータが、1だったらDDSへのDATA信号ラインを[H]にするルーチン。
(31)TABLEの定義(PC+OFFSET相当のデータを持って戻る)
PC+OFFSET
データテーブルのサブルーチンに来ると、プログラムカウンタに、Wregの値(オフセット)が加算されます。その加算結果をプログラムカウンタとしますので、そのテーブルポインタ(アドレス)で指定されたデータを示すようになります。
ADDWF PCL,F ;プログラムカウンタに、Wregの値(オフセット)を加算し、
その加算結果をプログラムカウンタする。
(32)ダミーデータ
テーブルポインタの値は、DDSへの入力データ(3ビットのアドレスデータ、4ビットのコマンドデータ、26ビットの周波数データ 計33ビット分)が記載されたテーブルの位置関係を指し示します。テーブルポインタ(アドレス)で指定されたデータの位置関係を対応させるために、ここにダミーを入れておきます。
(注)(22)の分岐命令により、テーブルポインタが0のときデータの読み込みルーチンを抜けてしまうため、ここのアドレス位置にデータを記載しても読み込みがされませんのでNOPとしています。
(33)f=10.000000MHz
ここのデータテーブルに、10MHzの周波数データを記載します。すなわち、
10000000を26ビットで表すと、(00100110001001011010000000)となります。
(34)コマンドC
コマンドCとは、メモリ1CHに26ビットの周波数データを書き込みこれを出力するDDS設定のコマンドです。
コマンドについての詳細は、こちらをご覧ください。→入力データのコマンドについて
(35)CS2,CS1,CS0 = 1,1,1
DDSのチップセレクトになります。ここでは、DDS側の設定で、CS2=「H」、CS1=「H」、CS0=「H」としていますので、シリアル入力のチップセレクトデータは、111となります。
DDSの動作確認
図6にDDSの出力波形(f = 10MHz)をオシロスコープで見たところです。ご覧のように波形にやや歪が見られますので、波形品位を重視するような用途には向きません。したがって、DDSキットをPLLの基準発振器とするように、波形品位に影響しない使い方をするほうが望ましいと思います。図7に示すように周波数の実測値は、9.999942MHzとなっています。周波数カウンタ(OPTOELECTRONICS社製 Model
Cub 1MHz-2.8GHz 9桁 ポケット周波数カウンタ: 秋月電子通商で購入)の測定誤差も含まれますが、DDSに使われている67.10886MHzの水晶発振器モジュールの周波数精度が、-5.8ppm程度と推測されます。使用されている発振器の仕様は不明ですが、通常の水晶発振器モジュールの周波数精度は±10ppm程度と考えられますので、それほど大きな誤差ではありません。
![]() |
![]() |
| 図6.DDS出力波形の観測 | 図7.DDS出力周波数の測定 |
![]() |
|
![]() |
|